﻿using Ionic.Zip;
using Ionic.Zlib;
using SharpEpub.XmlBuilder;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using XmlElement = SharpEpub.XmlBuilder.XmlElement;

namespace Pdf2epub.Epub
{
    public abstract class EpubBase
    {
        public TocOptions tocOption = TocOptions.ByFilename;
        protected ZipFile file;
        protected bool isDirty = false;

        private EpubMetadata metadata;

        private EpubTableOfContents tableOfContents;

        protected EpubBase()
        {
            Structure = new EpubStructure();
            file = new ZipFile();
        }

        public EpubMetadata Metadata
        {
            get
            {
                if (metadata == null)
                    return (metadata = new EpubMetadata(Structure, file, TableOfContents.GetBookId));
                metadata.UpdatStructure(Structure, file);
                return metadata;
            }
            set { metadata = value; }
        }

        public EpubStructure Structure { get; set; }

        public EpubTableOfContents TableOfContents
        {
            get
            {
                if (tableOfContents == null)
                    return (tableOfContents = new EpubTableOfContents(Structure, file, tocOption));
                tableOfContents.UpdatStructure(Structure, file);
                return tableOfContents;
            }
            set { tableOfContents = value; }
        }

        public byte[] BuildToBytes()
        {
            if (!isDirty) DoMainActions();
            MemoryStream stream = new MemoryStream();
            file.Save(stream);
            return stream.ToArray();
        }

        public void BuildToFile(string filename)
        {
            if (!isDirty) DoMainActions();
            file.Save(filename);
        }

        public Stream BuildToStream()
        {
            if (!isDirty) DoMainActions();
            MemoryStream stream = new MemoryStream();
            file.Save(stream);
            stream.Seek(0, SeekOrigin.Begin);
            return stream;
        }

        public void Clear()
        {
            file.RemoveSelectedEntries("*.*");
        }

        protected void BuildEpubStructure()
        {
            file = new ZipFile();
            file.AddEntry("mimetype", Resources.Mimetype).CompressionLevel = CompressionLevel.None;
            if (!string.IsNullOrEmpty(Structure.Directories.ContentFolder)) file.AddDirectoryByName(Structure.Directories.ContentFolder);
            file.AddDirectoryByName(Structure.Directories.MetaInfFolder);
            if (!string.IsNullOrEmpty(Structure.Directories.ImageFolder)) file.AddDirectoryByName(Structure.Directories.ImageFolderFullPath);
            if (!string.IsNullOrEmpty(Structure.Directories.CssFolder)) file.AddDirectoryByName(Structure.Directories.CssFolderFullPath);
        }

        protected abstract void DoMainActions();

        protected void GenerateContainerFile()
        {
            XmlDocument xmlDocument = new XmlDocument();
            var attributes = new Dictionary<string, string>();
            attributes["xmlns"] = Resources.ContainerNs;
            attributes["version"] = "1.0";
            XmlBuilder document = xmlDocument.CreateXmlBuilder("container", attributes);

            XmlElement rootFilesNode = xmlDocument.CreateXmlElement("rootfiles");
            document.AppendElement(rootFilesNode);

            var rootFileAttributes = new Dictionary<string, string>();
            rootFileAttributes["full-path"] = Structure.Files.OpfFileFullPath;
            rootFileAttributes["media-type"] = Resources.ContainerMediaType;

            XmlElement rootFileNode = xmlDocument.CreateXmlElement("rootfile", rootFileAttributes);
            rootFilesNode.AppendElement(rootFileNode);

            file.AddEntry(Structure.Files.ContainerFileFullPath, document.GetDocument().OuterXml);
        }

        protected void GenerateMetadataAndTocFiles(string htmlSourceDirectory)
        {
            TableOfContents.HtmlSourceFolder = htmlSourceDirectory;
            file.AddEntry(Structure.Files.NcxFileFullPath, TableOfContents.BuildAndGetContent());
            file.AddEntry(Structure.Files.OpfFileFullPath, Metadata.BuildAndGetContent());
        }
    }
}